/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/*
*  \class	CLine
*  \author 	Jari Saarinen
*  \date 	Thu Jun 15 22:16:18 2006

*  \version: 	0.1  
*/

#include <math.h>
#include "CLine.h"




CLine::CLine()
{
}


CLine::~CLine()
{
	
}
/**
* Returns the line structure of this line
*/
TLine CLine::getTLine(){	
	return this->line;
}

/**
* Sets the TLine to CLine
*/
void CLine::setLine(TLine l){
	this->line = l;
}

/**
* Set the line using line start and end points
*/
void CLine::setLine(float x1, float y1, float x2, float y2){
	this->line.initTLine(x1,y1,x2,y2);
}

/**
* The angle of the line. The angle is calculated from starting point (x1,y1)
* towards end point (x2,y2)
* @return TAngle class 
*/
TAngle CLine::getLineAngle(){
	TAngle a;
	float ang, dy,dx;
	
	dy = line.y2 - line.y1;
	dx = line.x2 - line.x1;

	ang =(float) atan2(dy,dx);
	a.setValue( ang );
	return a;
}

/**
* Returns the length of the line squared
*/
float CLine::getLineLengthSquared(){
	return (line.x1 - line.x2)*(line.x1 - line.x2) + (line.y1 - line.y2)*(line.y1 - line.y2);
}

/**
* Returns the length of the line
*/
float CLine::getLineLength(){
	return ((float)sqrt(this->getLineLengthSquared()));	
}

/**
* Calculates the distance of the point (x,y) from line L
* @param p	The 2D-point from where the distance is calculated
* @return distance if succesful, else -1
*/
float CLine::pointDistanceFromLine(TCoord2D p){
	TLine L;

	L = this->line; 
	if(sqrt(L.p.a*L.p.a + L.p.b*L.p.b)>0)
		return (float) (fabs( L.p.a * p.getX() + L.p.b * p.getY() + L.p.c )/sqrt(L.p.a*L.p.a + L.p.b*L.p.b));
	else return -1;
}	

/** 
* Returns the  angle difference between this line and another line 
* @param l2		CLine
**/
TAngle CLine::angleDiff(CLine l){
	float dx1, dy1;
	float dx2, dy2;
	TLine l1;
	TLine l2;
	TAngle a;

	l1 = this->line;
	l2 = l.getTLine();

	dx1 = l1.x1 - l1.x2;
	dy1 = l1.y1 - l1.y2;
	
	dx2 = l2.x1 - l2.x2;
	dy2 = l2.y1 - l2.y2;
	a.setValue((float)acos(fabs (dx1*dx2+dy1*dy2) / ( sqrt(dx1*dx1+dy1*dy1) * sqrt(dx2*dx2+dy2*dy2) ) ));
	return a;
}


/**
* Rotates line around coordinate P
* @param P Coordinate around which the rotation is done
* @param alpha rotation angle
*/
void CLine::rotate(TCoord2D P, float alpha){
	TLine L;
	float cos_alpha = (float)cos(alpha);
	float sin_alpha = (float)sin(alpha);
	
	L = this->line;

	this->line.x1 = cos_alpha * (L.x1 - P.getX()) - sin_alpha * (L.y1 - P.getY()) + P.getX();
	this->line.y1 = sin_alpha * (L.x1 - P.getX()) + cos_alpha * (L.y1 - P.getY()) + P.getY(); 
 
	this->line.x2 = cos_alpha * (L.x2 - P.getX()) - sin_alpha * (L.y2 - P.getY()) + P.getX();
	this->line.y2 = sin_alpha * (L.x2 - P.getX()) + cos_alpha * (L.y2 - P.getY()) + P.getY();
}

/**
* checks if coordinate P belongs to the Line
* Returns 1 if it does 0 if not
*/
int CLine::isInLine(TCoord2D P){
	float mx1,mx2,my1,my2;
	float L,AC,AB;
	float x0,y0;
	TLine Line;

	Line = this->line;

	x0 = P.getX();
	y0 = P.getY();

	mx2=Line.x1; 
	my2=Line.y1; 
	mx1=Line.x2; 
	my1=Line.y2; 
				
	L=( (mx2-mx1)*(mx2-mx1) + (my2-my1)*(my2-my1) );
	AC=( (x0-mx2)*(x0-mx2) + (y0-my2)*(y0-my2) );
	AB=( (x0-mx1)*(x0-mx1) + (y0-my1)*(y0-my1) );
	
	if(AC<=L && AB<=L ) return 1; // yes it is in line
	else 
		return 0;
}


/**
* Calculates point (coordinate) from the TLine line, which is closest 
* to the TCoord2D pos
*
* returns the TCoord2D. 
**/  				
TCoord2D CLine::shortestPointFromLine(TCoord2D pos){
	TCoord2D point;
	float k,b, x,y;
	
	if(fabs(line.p.b)> 0.00001 && fabs(line.p.a)>0.00001){
		k = line.p.b/line.p.a; //Paitsi jos b=0
		b = pos.getY() - k * pos.getX();
		
		x = -(b*line.p.b+line.p.c)/(line.p.a+line.p.b*k);
		y = k*x+b;
	}
	else if( fabs(line.p.b)  < 0.00001){
		x = -line.p.c/line.p.a;
		y = pos.getY();
	}
	else{
		x = pos.getX();
		y = -line.p.c/line.p.b;
	}
	
	point.setCoord(x,y);

	return point;
}
